/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点，可申请商业授权，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.proplan.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.security.core.parameters.P;
import vip.xiaonuo.core.context.login.LoginContextHolder;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PoiUtil;

import vip.xiaonuo.modular.planrel.entity.PlanRel;
import vip.xiaonuo.modular.planrel.mapper.PlanRelMapper;
import vip.xiaonuo.modular.planrel.param.PlanRelParam;
import vip.xiaonuo.modular.planrel.service.PlanRelService;
import vip.xiaonuo.modular.pro.entity.Pro;
import vip.xiaonuo.modular.pro.mapper.ProMapper;
import vip.xiaonuo.modular.pro.service.ProService;
import vip.xiaonuo.modular.proplan.entity.ProPlan;
import vip.xiaonuo.modular.proplan.enums.ProPlanExceptionEnum;
import vip.xiaonuo.modular.proplan.mapper.ProPlanMapper;
import vip.xiaonuo.modular.proplan.param.ProPlanParam;
import vip.xiaonuo.modular.proplan.result.ProPlanResult;
import vip.xiaonuo.modular.proplan.service.ProPlanService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.modular.task.entity.Task;
import vip.xiaonuo.modular.task.enums.TaskStatusEnum;
import vip.xiaonuo.modular.task.mapper.TaskMapper;
import vip.xiaonuo.modular.task.service.TaskService;
import vip.xiaonuo.modular.workorder.entity.WorkOrder;
import vip.xiaonuo.modular.workorder.enums.WorkOrderStatusEnum;
import vip.xiaonuo.modular.workorder.enums.WorkOrderTypeEnum;
import vip.xiaonuo.modular.workorder.mapper.WorkOrderMapper;
import vip.xiaonuo.modular.workorder.param.WorkOrderParam;
import vip.xiaonuo.modular.workorder.result.WorkOrderResult;
import vip.xiaonuo.modular.workorder.service.WorkOrderService;
import vip.xiaonuo.modular.workorderbill.entity.WorkOrderBill;
import vip.xiaonuo.modular.workorderbill.enums.WorkOrderBillEnum;
import vip.xiaonuo.modular.workorderbill.service.WorkOrderBillService;
import vip.xiaonuo.modular.workreport.entity.WorkReport;
import vip.xiaonuo.modular.workreport.mapper.WorkReportMapper;
import vip.xiaonuo.modular.workreport.service.WorkReportService;
import vip.xiaonuo.modular.workstep.entity.WorkStep;
import vip.xiaonuo.modular.workstep.service.WorkStepService;
import vip.xiaonuo.modular.worksteproute.entity.WorkStepRoute;
import vip.xiaonuo.modular.worksteproute.mapper.WorkStepRouteMapper;
import vip.xiaonuo.modular.worksteproute.service.WorkStepRouteService;
import vip.xiaonuo.sys.modular.user.entity.SysUser;
import vip.xiaonuo.sys.modular.user.service.SysUserService;
import vip.xiaonuo.util.AutoCode;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 生产计划service接口实现类
 *
 * @author 嘉欣
 * @date 2022-07-19 11:40:28
 */
@Service
public class ProPlanServiceImpl extends ServiceImpl<ProPlanMapper, ProPlan> implements ProPlanService {
    @Resource
    private WorkReportService workReportService;
    @Resource
    private WorkOrderService workOrderService;
    @Resource
    private WorkStepService workStepService;
    @Resource
    private WorkStepRouteService workStepRouteService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private TaskService taskService;
    @Resource
    private WorkOrderBillService workOrderBillService;
    @Resource
    private ProService proService;

    @Override
    public PageResult<ProPlanResult> page(ProPlanParam proPlanParam) {
        QueryWrapper<ProPlan> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(proPlanParam)) {
            // 根据单据编号 查询
            if (ObjectUtil.isNotEmpty(proPlanParam.getCode())) {
                queryWrapper.lambda().like(ProPlan::getCode, proPlanParam.getCode());
            }
            // 根据备注 查询
            if (ObjectUtil.isNotEmpty(proPlanParam.getRemarks())) {
                queryWrapper.lambda().like(ProPlan::getRemarks, proPlanParam.getRemarks());
            }
        }
        queryWrapper.orderByDesc("a.create_time");
        //进行二次数据处理
        //取到查到的数据
        Page<ProPlanResult> page = this.baseMapper.page(PageFactory.defaultPage(), queryWrapper);
        /*
         * ===============================================处理数据的准备工作 start ======================================
         */

        //查询所有的用户姓名保存至sysUserMap
        Map<Long, String> sysUserMap = new HashMap<>();
        List<SysUser> sysUserList = sysUserService.list();
        if (ObjectUtil.isNotEmpty(sysUserList)) {
            sysUserList.forEach(item -> {
                //key:用户id  value：用户名称
                sysUserMap.put(item.getId(), item.getName());
            });
        }
        //查询所有的生产计划保存至proPlanMap
        Map<Long, ProPlan> proPlanMap = new HashMap<>();
        List<ProPlan> proPlanList = this.list();
        if (ObjectUtil.isNotEmpty(proPlanList)) {
            proPlanList.forEach(item -> proPlanMap.put(item.getId(), item));
        }
        // 生产计划为 2
        // 先取到所有的关于生产计划的单据
        QueryWrapper<WorkOrderBill> billQueryWrapper = new QueryWrapper<>();
        billQueryWrapper.lambda().eq(WorkOrderBill::getType, WorkOrderBillEnum.ProPlan.getCode());
        List<WorkOrderBill> billList = workOrderBillService.list(billQueryWrapper);
        // 设定一个Map key 为生产计划id,value 为 该生产计划ID的所有的单据
        Map<Long, List<WorkOrderBill>> billGroupByInvId = billList.stream().collect(Collectors.groupingBy(WorkOrderBill::getBillId));
        // 设定一个Map key 为工单id,value 为 该工单的所有任务
        QueryWrapper<Task> taskQueryWrapper = new QueryWrapper<>();
        taskQueryWrapper.lambda().orderByAsc(Task::getSortNum);
        List<Task> taskList = taskService.list(taskQueryWrapper);
        Map<Long, List<Task>> taskMap = taskList.stream().collect(Collectors.groupingBy(Task::getWorkOrderId));
        // 设定一个Map key 为单据id,value 为 工单
        List<WorkOrder> workOrderList = workOrderService.list();
        Map<Long, WorkOrder> workOrderMap = workOrderList.stream().collect(Collectors.toMap(WorkOrder::getBillId, a -> a, (k1, k2) -> k1));
        /*
         * ===============================================处理数据的准备工作 end ======================================
         */
        page.getRecords().forEach(item -> {
            // 记录结束工单数
            AtomicReference<Integer> endWorkerorderNum = new AtomicReference<>(0);
            Long id = item.getId();
            if (ObjectUtil.isEmpty(id)) {
                return;
            }
            List<WorkOrderResult> workOrders = new ArrayList<>();
            // 创建一个数组同来储存工单进度
            List<Integer> progressRateList = new ArrayList<>();
            //获得该条生产计划下的对应工单列表
            if (ObjectUtil.isNotNull(billGroupByInvId.get(item.getId()))) {
                billGroupByInvId.get(item.getId()).forEach(bill -> {
                    // workOrderMap 中获取工单id
                    WorkOrder workOrder = workOrderMap.get(bill.getId());
                    if(ObjectUtil.isNotNull(workOrder)){
                        if (WorkOrderStatusEnum.FINISH.getCode().equals(workOrder.getStatus())) {
                            endWorkerorderNum.set(endWorkerorderNum.get() + 1);
                        }
                    // 根据工单id查找任务
                    if (ObjectUtil.isNotNull(taskMap.get(workOrder.getId()))) {
                        taskMap.get(workOrder.getId()).forEach(task -> {
                            int progressRate = 0;
                            Integer plaNum = task.getPlaNum();
                            Integer goodNum = task.getGoodNum();
                            if (ObjectUtil.isNotEmpty(plaNum) && ObjectUtil.isNotEmpty(goodNum)) {
                                progressRate = (100 * goodNum) / plaNum;
                            }
                            progressRateList.add(progressRate);
                        });
                    }
                    // 把工单任务进度放进 workOrderResult
                    WorkOrderResult workOrderResult = new WorkOrderResult();
                    BeanUtil.copyProperties(workOrder, workOrderResult);
                    workOrderResult.setProgressRateList(progressRateList);
                    workOrders.add(workOrderResult);
                    }

                });
            }

            if (ObjectUtil.isEmpty(workOrders)) {
                return;
            }
            item.setWorkOrderList(workOrders);
            item.setEndWorkerorderNum(endWorkerorderNum.get());
            item.setCreateUserName(sysUserMap.get(item.getCreateUser()));
            item.setUpdateUserName(sysUserMap.get(item.getUpdateUser()));

        });

        return new PageResult<>(page);
    }

    @Override
    public List<ProPlan> list(ProPlanParam proPlanParam) {
        return this.list();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(ProPlanParam proPlanParam) {
        //防止生产计划为空
        if (ObjectUtil.isEmpty(proPlanParam.getWorkOrderList())) {
            throw new ServiceException(1, "工单不能为空");
        }
        //如果编码为空，手动添加编码
        if (ObjectUtil.isEmpty(proPlanParam.getCode())) {
            proPlanParam.setCode(AutoCode.getCodeByService("dw_pro_plan", this.getClass(), 0));
        }
        checkParam(proPlanParam, false);
        //保存至生产计划表
        ProPlan proPlan = new ProPlan();
        BeanUtil.copyProperties(proPlanParam, proPlan);
        this.save(proPlan);
        List<WorkOrder> workOrderList = proPlanParam.getWorkOrderList();
        addOrUpdateWrok(proPlan, workOrderList, false);
    }

    private void addOrUpdateWrok(ProPlan proPlan, List<WorkOrder> workOrderList, boolean isExcludeSelf) {
        // 设置一个addWorkOrderList 为批量增加工单做准备
        List<WorkOrder> addWorkOrderList = new ArrayList<>();
        // 设置一个addWorkOrderBill 为批量增加工单做准备
        List<WorkOrderBill> addWorkOrderBillList = new ArrayList<>();
        // 开始添加的工单单据关系
        workOrderList.forEach(workOrder -> {
            WorkOrderBill workOrderBill = new WorkOrderBill();
            workOrderBill.setType(WorkOrderBillEnum.ProPlan.getCode());
            workOrderBill.setProId(workOrder.getProId());
            workOrderBill.setBillId(proPlan.getId());
            addWorkOrderBillList.add(workOrderBill);
            addWorkOrderList.add(workOrder);
        });
        // 批量添加 工单单据关系
        workOrderBillService.saveBatch(addWorkOrderBillList);
        // 工单编号使用
        String template = "{}-{}";
        AtomicReference<Integer> workOrderNumber = new AtomicReference<>(0);
        // 如果是编辑调用的添加需要获得当前数据库的最大值
        if (isExcludeSelf) {
            String proPlanCode = proPlan.getCode() + "-";
            QueryWrapper<WorkOrder> WorkCodeQW = new QueryWrapper<>();
            WorkCodeQW.lambda().like(WorkOrder::getWorkOrderNo, proPlanCode);
            List<WorkOrder> workOrders = workOrderService.list(WorkCodeQW);
            List<Integer> numberInt = new ArrayList<>();
            workOrders.forEach(workOrder -> numberInt.add(Integer.valueOf(StrUtil.sub(workOrder.getWorkOrderNo(), proPlanCode.length(), workOrder.getWorkOrderNo().length()))));

            // 查询数据库中编码最大值
            if (ObjectUtil.isNotEmpty(numberInt)) {
                Integer maxNumber = Collections.max(numberInt);
                workOrderNumber.set(workOrderNumber.get() + maxNumber);
            }
        }
        // 工单中产品类型需要
        List<Pro> proList = proService.list();
        Map<Long, Pro> proMap = proList.stream().collect(Collectors.toMap(Pro::getId, a -> a, (k1, k2) -> k1));
        // 批量添加工单开始 因为要用到所有 所以不用 forEach
        for (int i = 0; i < addWorkOrderList.size(); i++) {
            addWorkOrderList.get(i).setType(WorkOrderTypeEnum.SEQUENTIAL_WORK_ORDER.getCode());
            addWorkOrderList.get(i).setWorkOrderNo(StrUtil.format(template, proPlan.getCode(), workOrderNumber.get() + 1));
            workOrderNumber.set(workOrderNumber.get() + 1);
            addWorkOrderList.get(i).setProTypeId(proMap.get(addWorkOrderList.get(i).getProId()).getProTypeId());
            addWorkOrderList.get(i).setBillId(addWorkOrderBillList.get(i).getId());
            addWorkOrderList.get(i).setStatus(WorkOrderStatusEnum.NOT_START.getCode());
            addWorkOrderList.get(i).setNextPerson(LoginContextHolder.me().getSysLoginUserId());
            addWorkOrderList.get(i).setPersonCharge(LoginContextHolder.me().getSysLoginUserId());
            addWorkOrderList.get(i).setOrderTime(new Date());
        }
        // 批量添加工单
        workOrderService.saveBatch(addWorkOrderList);
        // 批量添加任务开始
        // 设置一个addTaskList 为批量增加工单做准备
        List<Task> addTaskList = new ArrayList<>();
        // 获取工艺路线与工序关系，并且进行排序
        QueryWrapper<WorkStepRoute> workStepRouteQueryWrapper = new QueryWrapper<>();
        //升序
        workStepRouteQueryWrapper.lambda().orderByAsc(WorkStepRoute::getSortNum);
        List<WorkStepRoute> workStepRouteList = workStepRouteService.list(workStepRouteQueryWrapper);
        // 设定一个Map key 为工艺路线id,value 为 该工艺路线下的所有 工序工艺路线关系
        Map<Long, List<WorkStepRoute>> workStepRoutMap = workStepRouteList.stream().collect(Collectors.groupingBy(WorkStepRoute::getWorkRouteId));
        // 设定一个Map key 为工序工艺路线关系id,value 为 所对应的工序
        List<WorkStep> workStepList = workStepService.list();
        Map<Long, WorkStep> workStepMap = workStepList.stream().collect(Collectors.toMap(WorkStep::getId, a -> a, (k1, k2) -> k1));
        // 开始添加
        addWorkOrderList.forEach(workOrder -> {
            if(ObjectUtil.isNull(workStepRoutMap)||ObjectUtil.isNull(proMap.get(workOrder.getProId()).getWorkRouteId())){
                throw new ServiceException(10,"请添加工艺路线");
            }
            workStepRoutMap.get(proMap.get(workOrder.getProId()).getWorkRouteId()).forEach(workStepRoute -> {
                Task task = new Task();
                task.setSortNum(workStepRoute.getSortNum());
                task.setWorkOrderId(workOrder.getId());
                task.setProId(workOrder.getProId());
                task.setProTypeId(workOrder.getProTypeId());
                task.setWorkStepId(workStepRoute.getWorkStepId());
                task.setPlaNum(workOrder.getPlaNum());
                task.setPlaStartTime(workOrder.getPlaStartTime());
                task.setPlaEndTime(workOrder.getPlaEndTime());
                task.setStatus(TaskStatusEnum.NOT_START.getCode());
                task.setReportRight(workStepMap.get(workStepRoute.getWorkStepId()).getReportRight());
                task.setGoodNum(0);
                task.setBadNum(0);
                addTaskList.add(task);
            });
        });
        List<String> taskCodes = AutoCode.getCodeByService("dw_task", this.getClass(), "code", addTaskList.size());
        for (int i = 0; i < taskCodes.size(); i++) {
            addTaskList.get(i).setCode(taskCodes.get(i));
        }
        // 添加任务完成
        taskService.saveBatch(addTaskList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<ProPlanParam> proPlanParamList) {
        // 查找所有生产计划关系
        QueryWrapper<WorkOrderBill> workOrderBillQW = new QueryWrapper<>();
        workOrderBillQW.lambda().eq(WorkOrderBill::getType, WorkOrderBillEnum.ProPlan.getCode());
        List<WorkOrderBill> billList = workOrderBillService.list();
        //map  key:生产计划id   value：生产计划关系列表
        Map<Long, List<WorkOrderBill>> billGroupByInvId = billList.stream().collect(Collectors.groupingBy(WorkOrderBill::getBillId));
        //map  key:关联单据id   value：
        List<WorkOrder> workOrderList = workOrderService.list();
        Map<Long, WorkOrder> workOrderMap = workOrderList.stream().collect(Collectors.toMap(WorkOrder::getBillId, a -> a, (k1, k2) -> k1));
        // 记录删除装配工单的条件
        QueryWrapper<ProPlan> proPlanQueryWrapper = new QueryWrapper<>();
        // 记录删除工单单据关系的条件
        QueryWrapper<WorkOrderBill> workOrderBillQueryWrapper = new QueryWrapper<>();
        // 记录删除工单的条件
        QueryWrapper<WorkOrder> workOrderQueryWrapper = new QueryWrapper<>();
        // 记录删除任务的条件
        QueryWrapper<Task> taskQueryWrapper = new QueryWrapper<>();
        // 记录删除报工的条件
        QueryWrapper<WorkReport> workReportQueryWrapper = new QueryWrapper<>();
        proPlanParamList.forEach((proPlanParam) -> {
            // 根据工单单据详情查找相应的工单
            if (ObjectUtils.isNotEmpty(billGroupByInvId.get(proPlanParam.getId()))){
                billGroupByInvId.get(proPlanParam.getId()).forEach(item -> {
                    // 记录删除工单的条件
                    workOrderQueryWrapper.lambda().eq(WorkOrder::getBillId, item.getId()).or();
                    WorkOrder workOrder = workOrderMap.get(item.getId());
                    // 记录删除任务的条件
                    taskQueryWrapper.lambda().eq(Task::getWorkOrderId, workOrder.getId()).or();
                    // 记录删除报工的条件
                    workReportQueryWrapper.lambda().eq(WorkReport::getWorkOrderId, workOrder.getId()).or();
                });

            }
            // 记录删除工单单据关系的条件
            workOrderBillQueryWrapper.lambda().eq(WorkOrderBill::getBillId, proPlanParam.getId()).or();
            // 记录删除装配工单的条件
            proPlanQueryWrapper.lambda().eq(ProPlan::getId, proPlanParam.getId()).or();
        });
        // 删除报工
        workReportService.remove(workReportQueryWrapper);
        // 删除任务
        taskService.remove(taskQueryWrapper);
        // 删除工单
        workOrderService.remove(workOrderQueryWrapper);
        // 删除工单单据关系
        workOrderBillService.remove(workOrderBillQueryWrapper);
        // 删除装配工单
        this.remove(proPlanQueryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(ProPlanParam proPlanParam) {
        ProPlan proPlan = this.queryProPlan(proPlanParam);
        // ProPlan proPlan = new ProPlan();
        BeanUtil.copyProperties(proPlanParam, proPlan);
        this.updateById(proPlan);
        checkParam(proPlanParam, true);
        //如果编码为空，手动添加编码
        if (ObjectUtil.isEmpty(proPlanParam.getCode())) {
            throw new ServiceException(10, "编号不能为空，请输入编号");
        }
        //该生产计划id
        Long proPlanId = proPlan.getId();
        //需要添加的新的工单
        List<WorkOrder> addWorkOrderList = new ArrayList<>();
        //需要删除的工单的id
        List<Long> deleteWorkOrderIdList = new ArrayList<>();
        //需要编辑的工单
        List<WorkOrder> editWorkOrderList = new ArrayList<>();
        //查找该生产计划下的工单关系条件
        QueryWrapper<WorkOrderBill> workOrderBillQueryWrapper = new QueryWrapper<>();
        workOrderBillQueryWrapper.lambda().eq(WorkOrderBill::getBillId, proPlanId);
        //获取该生产计划下所有的工单关系
        List<WorkOrderBill> workOrderBills = workOrderBillService.list(workOrderBillQueryWrapper);
        //查找对应的工单
        QueryWrapper<WorkOrder> workOrderQueryWrapper = new QueryWrapper<>();
        workOrderBills.forEach(workOrderBill -> workOrderQueryWrapper.lambda().eq(WorkOrder::getBillId, workOrderBill.getId()).or());
        List<WorkOrder> oldWorkOrderList = workOrderService.list(workOrderQueryWrapper);
        oldWorkOrderList.forEach(workOrder -> {
            //将原来的工单id添加至删除列表中
            deleteWorkOrderIdList.add(workOrder.getId());
        });
        //遍历前端传来的所有的
        proPlanParam.getWorkOrderList().forEach(workOrder -> {
            //若id为空则需要新增
            if (ObjectUtil.isEmpty(workOrder.getId())) {
                addWorkOrderList.add(workOrder);
            } else if (ObjectUtil.isNotEmpty(workOrder.getId())) {
                //需要修改的工单
                editWorkOrderList.add(workOrder);
                //从删除列表里移除
                deleteWorkOrderIdList.remove(workOrder.getId());
            }
        });
        //查找所有工单
        List<WorkOrder> workOrders = workOrderService.list();
        //将工单与工单单据id对应的map
        Map<Long, WorkOrder> workOrderMap = workOrders.stream().collect(Collectors.toMap(WorkOrder::getId, a -> a, (k1, k2) -> k1));
//        //查找所有任务
//        List<Task> tasks=taskService.list();
//        //key:工单id value:任务list
//        Map<Long,List<Task>> taskMap=tasks.stream().collect(Collectors.groupingBy(Task::getWorkOrderId));
        // 设定一个Map key 为工单id,value 为 该工单的所有报工
        List<WorkReport> workReportList = workReportService.list();
        Map<Long, List<WorkReport>> workReporMap = workReportList.stream().collect(Collectors.groupingBy(WorkReport::getWorkOrderId));
        // 设定一个删除任务的 deleteTaskListQW
        QueryWrapper<Task> deleteTaskListQW = new QueryWrapper<>();
        // 设定一个删除报工的 deleteWorkReportQW
        QueryWrapper<WorkReport> deleteWorkReportQW = new QueryWrapper<>();
        //需要新增的任务
        List<Task> addTaskList = new ArrayList<>();
        // 获取工艺路线与工序关系，并且进行排序
        QueryWrapper<WorkStepRoute> workStepRouteQueryWrapper = new QueryWrapper<>();
        //升序
        workStepRouteQueryWrapper.lambda().orderByAsc(WorkStepRoute::getSortNum);
        List<WorkStepRoute> workStepRouteList = workStepRouteService.list(workStepRouteQueryWrapper);
        // 设定一个Map key 为工艺路线id,value 为 该工艺路线下的所有 工序工艺路线关系
        Map<Long, List<WorkStepRoute>> workStepRoutMap = workStepRouteList.stream().collect(Collectors.groupingBy(WorkStepRoute::getWorkRouteId));
        // 设定一个Map key 为工序工艺路线关系id,value 为 所对应的工序
        List<WorkStep> workStepList = workStepService.list();
        Map<Long, WorkStep> workStepMap = workStepList.stream().collect(Collectors.toMap(WorkStep::getId, a -> a, (k1, k2) -> k1));
        // 工单中产品类型需要
        List<Pro> proList = proService.list();
        Map<Long, Pro> proMap = proList.stream().collect(Collectors.toMap(Pro::getId, a -> a, (k1, k2) -> k1));
        AtomicBoolean flag = new AtomicBoolean(false);
        editWorkOrderList.forEach(workOrder -> {
            // 判断产品是否发生变化
            if (!workOrder.getProId().equals(workOrderMap.get(workOrder.getId()).getProId()) && ObjectUtil.isNotEmpty(workOrderMap.get(workOrder.getId()).getProId())) {
                // 产品变了，就删除原先的所有任务
                deleteTaskListQW.lambda().eq(Task::getWorkOrderId, workOrder.getId()).or();
                flag.set(true);
                // 产品变了，就删除原先的所有报工
                if (ObjectUtil.isNotEmpty(workReporMap.get(workOrder.getId()))) {
                    deleteWorkReportQW.lambda().eq(WorkReport::getWorkOrderId, workOrder.getId()).or();
                }
                // 添加任务
                workStepRoutMap.get(proMap.get(workOrder.getProId()).getWorkRouteId()).forEach(workStepRoute -> {
                    Task task = new Task();
                    task.setSortNum(workStepRoute.getSortNum());
                    task.setWorkOrderId(workOrder.getId());
                    task.setProId(workOrder.getProId());
                    task.setProTypeId(workOrder.getProTypeId());
                    task.setWorkStepId(workStepRoute.getWorkStepId());
                    task.setPlaNum(workOrder.getPlaNum());
                    task.setPlaStartTime(workOrder.getPlaStartTime());
                    task.setPlaEndTime(workOrder.getPlaEndTime());
                    task.setStatus(TaskStatusEnum.NOT_START.getCode());
                    task.setReportRight(workStepMap.get(workStepRoute.getWorkStepId()).getReportRight());
                    task.setGoodNum(0);
                    task.setBadNum(0);
                    addTaskList.add(task);
                });
                List<String> taskCodes = AutoCode.getCodeByService("dw_task", this.getClass(), "code", addTaskList.size());
                for (int i = 0; i < taskCodes.size(); i++) {
                    addTaskList.get(i).setCode(taskCodes.get(i));
                }
            }
        });
        // 删除任务
        if (flag.get()) {
            taskService.remove(deleteTaskListQW);
        }
        // 添加任务
        if (ObjectUtil.isNotEmpty(addTaskList)) {
            taskService.saveBatch(addTaskList);
        }
        // 删除报工
        workReportService.remove(deleteWorkReportQW);
        if (ObjectUtil.isNotEmpty(editWorkOrderList)) {
            workOrderService.updateBatchById(editWorkOrderList);
        }
        // 添加
        if (ObjectUtil.isNotEmpty(addWorkOrderList)) {
            addOrUpdateWrok(proPlan, addWorkOrderList, true);
        }
        // 删除
        if (ObjectUtil.isNotEmpty(deleteWorkOrderIdList)) {
            updateDelete(deleteWorkOrderIdList);
        }
    }

    private void updateDelete(List<Long> deleteWorkOrderIdList) {
        // 设定一个Map key 为工单id,value 为 工单
        List<WorkOrder> workOrderList = workOrderService.list();
        Map<Long, WorkOrder> workOrderMap = workOrderList.stream().collect(Collectors.toMap(WorkOrder::getId, a -> a, (k1, k2) -> k1));
        // 需要被删除任务的条件
        QueryWrapper<Task> taskQueryWrapper = new QueryWrapper<>();
        // 需要被删除报工的条件
        QueryWrapper<WorkReport> workReportQueryWrapper = new QueryWrapper<>();
        List<Task> taskList = taskService.list();
        Map<Long, List<Task>> longListMap = taskList.stream().collect(Collectors.groupingBy(Task::getWorkOrderId));
        List<Long> deleteTaskList = new ArrayList<>();
        // 需要被删除工单单据关系的条件
        List<Long> workOrderBillId = new ArrayList<>();
        deleteWorkOrderIdList.forEach(workOrderId -> {
            // 添加需要删除的任务
            workReportQueryWrapper.lambda().eq(WorkReport::getWorkOrderId, workOrderId).or();
            // 添加需要删除的报工
            taskQueryWrapper.lambda().eq(Task::getWorkOrderId, workOrderId);
            if (ObjectUtil.isNotEmpty(longListMap.get(workOrderId))){
                longListMap.get(workOrderId).forEach(task -> deleteTaskList.add(task.getId()));
            }
            // 添加需要删除的工单关系
            workOrderBillId.add(workOrderMap.get(workOrderId).getBillId());
        });
        // 删除报工
        workReportService.remove(workReportQueryWrapper);
        // 删除任务
        taskService.removeByIds(deleteTaskList);
        // 删除工单
        workOrderService.removeByIds(deleteWorkOrderIdList);
        // 删除工单单据关系
        workOrderBillService.removeByIds(workOrderBillId);
    }

    @Override
    public ProPlan detail(ProPlanParam proPlanParam) {
        return this.queryProPlan(proPlanParam);
    }

    /**
     * 获取生产计划
     *
     * @author 嘉欣
     * @date 2022-07-19 11:40:28
     */
    private ProPlan queryProPlan(ProPlanParam proPlanParam) {
        ProPlan proPlan = this.getById(proPlanParam.getId());
        if (ObjectUtil.isNull(proPlan)) {
            throw new ServiceException(ProPlanExceptionEnum.NOT_EXIST);
        }
        return proPlan;
    }

    @Override
    public void export(ProPlanParam proPlanParam) {
        List<ProPlan> list = this.list(proPlanParam);
        PoiUtil.exportExcelWithStream("SnowyProPlan.xls", ProPlan.class, list);
    }

    private void checkParam(ProPlanParam proPlanParam, boolean isExcludeSelf) {
        //校验数据是否为空
        for (WorkOrder workOrder : proPlanParam.getWorkOrderList()) {
            if (ObjectUtil.isEmpty(workOrder.getProId())) {
                throw new ServiceException(3, "产品不能为空，请添加产品");
            }
            if (ObjectUtil.isEmpty(workOrder.getPlaNum()) || workOrder.getPlaNum() <= 0) {
                throw new ServiceException(4, "产品数量不能为空并且必须大于零，请重新输入");
            }
            if (ObjectUtil.isEmpty(workOrder.getPlaStartTime())) {
                throw new ServiceException(5, "计划开始时间不能为空");
            }
            if (ObjectUtil.isEmpty(workOrder.getPlaEndTime())) {
                throw new ServiceException(6, "计划结束时间不能为空");
            }
            //判断如果开始时间比结束时间晚抛出异常
            if (workOrder.getPlaStartTime().after(workOrder.getPlaEndTime()) || workOrder.getPlaStartTime().equals(workOrder.getPlaEndTime())) {
                throw new ServiceException(7, "计划结束时间必须大于等于计划开始时间1分钟");
            }

        }
        LambdaQueryWrapper<ProPlan> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //如果是编辑需要去除自己
        if (isExcludeSelf) {
            lambdaQueryWrapper.ne(ProPlan::getId, proPlanParam.getId());
        }
        lambdaQueryWrapper.eq(ProPlan::getCode, proPlanParam.getCode());
        int count = this.count(lambdaQueryWrapper);
        if (count >= 1) {
            throw new ServiceException(2, "唯一编号已存在");
        }


    }

}
